; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -relocation-model=pic -verify-machineinstrs < %s \
; RUN:   | FileCheck -check-prefixes=RV32I %s
; RUN: llc -mtriple=riscv64 -relocation-model=pic -verify-machineinstrs < %s \
; RUN:   | FileCheck -check-prefixes=RV64I %s

; Verifies that MachineLICM can hoist address generation pseudos out of loops.

@l = protected global i32 0, align 4

define void @test_lla(i32 signext %n) {
; RV32I-LABEL: test_lla:
; RV32I:       # %bb.0: # %entry
; RV32I-NEXT:    li a1, 0
; RV32I-NEXT:  .Lpcrel_hi0:
; RV32I-NEXT:    auipc a2, %pcrel_hi(l)
; RV32I-NEXT:  .LBB0_1: # %loop
; RV32I-NEXT:    # =>This Inner Loop Header: Depth=1
; RV32I-NEXT:    lw a3, %pcrel_lo(.Lpcrel_hi0)(a2)
; RV32I-NEXT:    addi a1, a1, 1
; RV32I-NEXT:    blt a1, a0, .LBB0_1
; RV32I-NEXT:  # %bb.2: # %ret
; RV32I-NEXT:    ret
;
; RV64I-LABEL: test_lla:
; RV64I:       # %bb.0: # %entry
; RV64I-NEXT:    li a1, 0
; RV64I-NEXT:  .Lpcrel_hi0:
; RV64I-NEXT:    auipc a2, %pcrel_hi(l)
; RV64I-NEXT:  .LBB0_1: # %loop
; RV64I-NEXT:    # =>This Inner Loop Header: Depth=1
; RV64I-NEXT:    lw a3, %pcrel_lo(.Lpcrel_hi0)(a2)
; RV64I-NEXT:    addiw a1, a1, 1
; RV64I-NEXT:    blt a1, a0, .LBB0_1
; RV64I-NEXT:  # %bb.2: # %ret
; RV64I-NEXT:    ret
entry:
  br label %loop

loop:
  %i = phi i32 [ %inc, %loop ], [ 0, %entry ]
  %0 = load volatile i32, ptr @l, align 4
  %inc = add nuw nsw i32 %i, 1
  %cmp = icmp slt i32 %inc, %n
  br i1 %cmp, label %loop, label %ret

ret:
  ret void
}

@g = global i32 0, align 4

define void @test_la(i32 signext %n) {
; RV32I-LABEL: test_la:
; RV32I:       # %bb.0: # %entry
; RV32I-NEXT:  .Lpcrel_hi1:
; RV32I-NEXT:    auipc a1, %got_pcrel_hi(g)
; RV32I-NEXT:    lw a1, %pcrel_lo(.Lpcrel_hi1)(a1)
; RV32I-NEXT:    li a2, 0
; RV32I-NEXT:  .LBB1_1: # %loop
; RV32I-NEXT:    # =>This Inner Loop Header: Depth=1
; RV32I-NEXT:    lw a3, 0(a1)
; RV32I-NEXT:    addi a2, a2, 1
; RV32I-NEXT:    blt a2, a0, .LBB1_1
; RV32I-NEXT:  # %bb.2: # %ret
; RV32I-NEXT:    ret
;
; RV64I-LABEL: test_la:
; RV64I:       # %bb.0: # %entry
; RV64I-NEXT:  .Lpcrel_hi1:
; RV64I-NEXT:    auipc a1, %got_pcrel_hi(g)
; RV64I-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi1)(a1)
; RV64I-NEXT:    li a2, 0
; RV64I-NEXT:  .LBB1_1: # %loop
; RV64I-NEXT:    # =>This Inner Loop Header: Depth=1
; RV64I-NEXT:    lw a3, 0(a1)
; RV64I-NEXT:    addiw a2, a2, 1
; RV64I-NEXT:    blt a2, a0, .LBB1_1
; RV64I-NEXT:  # %bb.2: # %ret
; RV64I-NEXT:    ret
entry:
  br label %loop

loop:
  %i = phi i32 [ %inc, %loop ], [ 0, %entry ]
  %0 = load volatile i32, ptr @g, align 4
  %inc = add nuw nsw i32 %i, 1
  %cmp = icmp slt i32 %inc, %n
  br i1 %cmp, label %loop, label %ret

ret:
  ret void
}

@ie = external thread_local(initialexec) global i32

define void @test_la_tls_ie(i32 signext %n) {
; RV32I-LABEL: test_la_tls_ie:
; RV32I:       # %bb.0: # %entry
; RV32I-NEXT:  .Lpcrel_hi2:
; RV32I-NEXT:    auipc a1, %tls_ie_pcrel_hi(ie)
; RV32I-NEXT:    lw a2, %pcrel_lo(.Lpcrel_hi2)(a1)
; RV32I-NEXT:    li a1, 0
; RV32I-NEXT:    add a2, a2, tp
; RV32I-NEXT:  .LBB2_1: # %loop
; RV32I-NEXT:    # =>This Inner Loop Header: Depth=1
; RV32I-NEXT:    lw a3, 0(a2)
; RV32I-NEXT:    addi a1, a1, 1
; RV32I-NEXT:    blt a1, a0, .LBB2_1
; RV32I-NEXT:  # %bb.2: # %ret
; RV32I-NEXT:    ret
;
; RV64I-LABEL: test_la_tls_ie:
; RV64I:       # %bb.0: # %entry
; RV64I-NEXT:  .Lpcrel_hi2:
; RV64I-NEXT:    auipc a1, %tls_ie_pcrel_hi(ie)
; RV64I-NEXT:    ld a2, %pcrel_lo(.Lpcrel_hi2)(a1)
; RV64I-NEXT:    li a1, 0
; RV64I-NEXT:    add a2, a2, tp
; RV64I-NEXT:  .LBB2_1: # %loop
; RV64I-NEXT:    # =>This Inner Loop Header: Depth=1
; RV64I-NEXT:    lw a3, 0(a2)
; RV64I-NEXT:    addiw a1, a1, 1
; RV64I-NEXT:    blt a1, a0, .LBB2_1
; RV64I-NEXT:  # %bb.2: # %ret
; RV64I-NEXT:    ret
entry:
  br label %loop

loop:
  %i = phi i32 [ %inc, %loop ], [ 0, %entry ]
  %0 = load volatile i32, ptr @ie, align 4
  %inc = add nuw nsw i32 %i, 1
  %cmp = icmp slt i32 %inc, %n
  br i1 %cmp, label %loop, label %ret

ret:
  ret void
}

@gd = external thread_local global i32

define void @test_la_tls_gd(i32 signext %n) nounwind {
; RV32I-LABEL: test_la_tls_gd:
; RV32I:       # %bb.0: # %entry
; RV32I-NEXT:    addi sp, sp, -16
; RV32I-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
; RV32I-NEXT:    sw s0, 8(sp) # 4-byte Folded Spill
; RV32I-NEXT:    sw s1, 4(sp) # 4-byte Folded Spill
; RV32I-NEXT:    sw s2, 0(sp) # 4-byte Folded Spill
; RV32I-NEXT:    mv s0, a0
; RV32I-NEXT:    li s2, 0
; RV32I-NEXT:  .Lpcrel_hi3:
; RV32I-NEXT:    auipc a0, %tls_gd_pcrel_hi(gd)
; RV32I-NEXT:    addi s1, a0, %pcrel_lo(.Lpcrel_hi3)
; RV32I-NEXT:  .LBB3_1: # %loop
; RV32I-NEXT:    # =>This Inner Loop Header: Depth=1
; RV32I-NEXT:    mv a0, s1
; RV32I-NEXT:    call __tls_get_addr@plt
; RV32I-NEXT:    lw a0, 0(a0)
; RV32I-NEXT:    addi s2, s2, 1
; RV32I-NEXT:    blt s2, s0, .LBB3_1
; RV32I-NEXT:  # %bb.2: # %ret
; RV32I-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
; RV32I-NEXT:    lw s0, 8(sp) # 4-byte Folded Reload
; RV32I-NEXT:    lw s1, 4(sp) # 4-byte Folded Reload
; RV32I-NEXT:    lw s2, 0(sp) # 4-byte Folded Reload
; RV32I-NEXT:    addi sp, sp, 16
; RV32I-NEXT:    ret
;
; RV64I-LABEL: test_la_tls_gd:
; RV64I:       # %bb.0: # %entry
; RV64I-NEXT:    addi sp, sp, -32
; RV64I-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
; RV64I-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
; RV64I-NEXT:    sd s1, 8(sp) # 8-byte Folded Spill
; RV64I-NEXT:    sd s2, 0(sp) # 8-byte Folded Spill
; RV64I-NEXT:    mv s0, a0
; RV64I-NEXT:    li s2, 0
; RV64I-NEXT:  .Lpcrel_hi3:
; RV64I-NEXT:    auipc a0, %tls_gd_pcrel_hi(gd)
; RV64I-NEXT:    addi s1, a0, %pcrel_lo(.Lpcrel_hi3)
; RV64I-NEXT:  .LBB3_1: # %loop
; RV64I-NEXT:    # =>This Inner Loop Header: Depth=1
; RV64I-NEXT:    mv a0, s1
; RV64I-NEXT:    call __tls_get_addr@plt
; RV64I-NEXT:    lw a0, 0(a0)
; RV64I-NEXT:    addiw s2, s2, 1
; RV64I-NEXT:    blt s2, s0, .LBB3_1
; RV64I-NEXT:  # %bb.2: # %ret
; RV64I-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
; RV64I-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
; RV64I-NEXT:    ld s1, 8(sp) # 8-byte Folded Reload
; RV64I-NEXT:    ld s2, 0(sp) # 8-byte Folded Reload
; RV64I-NEXT:    addi sp, sp, 32
; RV64I-NEXT:    ret
entry:
  br label %loop

loop:
  %i = phi i32 [ %inc, %loop ], [ 0, %entry ]
  %0 = load volatile i32, ptr @gd, align 4
  %inc = add nuw nsw i32 %i, 1
  %cmp = icmp slt i32 %inc, %n
  br i1 %cmp, label %loop, label %ret

ret:
  ret void
}
